/*@description: nginx 对于recv的接口封装 
 *@attention:
 *
 *
 *
 *
 *
 *
 *
 * Copyright (C) Igor Sysoev
 * Copyright (C) Nginx, Inc.
 */


#include <ngx_config.h>
#include <ngx_core.h>
#include <ngx_event.h>

/*@brief: nginx 接收接口
 *@para:ngx_connection_t *c :网络连接的上下文
 *		u_char *buf: 接收缓冲区
 *		size_t size: 接收缓冲区的大小
 *
 *@return value:
 */
ssize_t ngx_unix_recv(ngx_connection_t *c, u_char *buf, size_t size)
{
    ssize_t       n;
    ngx_err_t     err;
    ngx_event_t  *rev; 

    rev = c->read; //读事件;


#if (NGX_HAVE_EPOLLRDHUP) //IO多路复用的是EPOLL

    if (ngx_event_flags & NGX_USE_EPOLL_EVENT) {
        ngx_log_debug2(NGX_LOG_DEBUG_EVENT, c->log, 0, "recv: eof:%d, avail:%d",  rev->pending_eof, rev->available);
        if (!rev->available && !rev->pending_eof) {
            rev->ready = 0;
            return NGX_AGAIN;
        }
    }

#endif

    do {
        n = recv(c->fd, buf, size, 0);

        ngx_log_debug3(NGX_LOG_DEBUG_EVENT, c->log, 0, "recv: fd:%d %z of %uz", c->fd, n, size);

        if (n == 0) {
            rev->ready = 0;
            rev->eof = 1;

            return 0;
        }

        if (n > 0) {

#if (NGX_HAVE_EPOLLRDHUP)

            if ((ngx_event_flags & NGX_USE_EPOLL_EVENT) && ngx_use_epoll_rdhup)
            {
                if ((size_t) n < size) {
                    if (!rev->pending_eof) {
                        rev->ready = 0;
                    }

                    rev->available = 0;
                }
                return n;
            }

#endif
            if ((size_t) n < size && !(ngx_event_flags & NGX_USE_GREEDY_EVENT))
            {
                rev->ready = 0;
            }

            return n;
        }

        err = ngx_socket_errno;

        if (err == NGX_EAGAIN || err == NGX_EINTR) {
      		ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, err, "recv() not ready");
            n = NGX_AGAIN;

        } else {
            n = ngx_connection_error(c, err, "recv() failed");
            break;
        }

    } while (err == NGX_EINTR);

    rev->ready = 0;
    if (n == NGX_ERROR) {
        rev->error = 1;
    }
    return n;
}
